package app.auto.runner.base.intf;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import app.auto.annotation.Show;
//import app.auto.runner.base.utility.pinyin.PinyinHelper;

/**
 * Created by admin on 2017/3/2.
 */
public class MapBuilder<T> {

    private MapBuilder mapBuilder;

    private MapBuilder parentMapBuilder;
    private String key;
    private T currentKey;

    public T getCurrentKey() {
        return currentKey;
    }


    public static Map reverseMap(Map map) {
        return reverseMapPrivate(map);
    }

    private static Map reverseMapPrivate(Map map) {
        Map rt = new HashMap();

        for (Object e : map.entrySet()) {
            Map.Entry ey = ((Map.Entry) e);
            rt.put(ey.getValue(), ey.getKey());
        }
        return rt;
    }

    public MapBuilder newMapBuilder(T key) {
        return newMapBuilderPrivate(key);
    }

    private MapBuilder newMapBuilderPrivate(T key) {
        mapBuilder = MapBuilder.build();
        mapBuilder.setParentMapBuilder(this);
        add(key, mapBuilder.get());
        this.currentKey = key;
        return mapBuilder;
    }

    public MapBuilder setParentMapBuilder(MapBuilder<T> tMapBuilder) {
        this.parentMapBuilder = tMapBuilder;
        return this;
    }


    private MapBuilder ref;

    private ListBuilder listBuilder;

    public void setListBuilder(ListBuilder listBuilder) {
        this.listBuilder = listBuilder;
    }

    public ListBuilder getListHolder() {
        return listBuilder;
    }

    public static Map extractList(List extractJsonRightValue, FunCallback funCallback, String... s) {

        return extractListPrivate(extractJsonRightValue, funCallback, s);
    }

    private static Map extractListPrivate(List extractJsonRightValue, FunCallback funCallback, String[] s) {
        MapBuilder result = MapBuilder.build();
        for (Object l : extractJsonRightValue) {
            ListBuilder ll = ListBuilder.build();
            for (String s1 : s) {
                ll.add(((Map) l).get(s1));
            }
            String value = "";
            if (funCallback == null) {
                for (Object o1 : ll.get()) {
                    value += o1.toString();
                }
            } else {
                value = (String) funCallback.tracnsfer(ll.get());
            }
            result.add(value, l);
        }
        return result.get();
    }

    @Show
    public MapBuilder addMap(Map m) {
        if (m != null) {
            map.putAll(m);
        }
        return this;
    }

    public MapBuilder withMap(Map map) {
        return setMap(map);
    }

    @Show
    private MapBuilder setMap(Map map) {
        this.map = map;
        return this;
    }

    private static MapBuilder hold = new MapBuilder();

    public Map map = new TreeMap();

    public static MapBuilder newInstance() {
        return hold = new MapBuilder();
    }

    public static MapBuilder hold() {
        if (hold == null) {
            newInstance();
        }
        return hold;
    }


    public Map<Object, Integer> indices;
    public Map<Object, String> pinyin;


    public Map<Object, Integer> getIndices() {
        return indices;
    }

    public static MapBuilder build() {
        final MapBuilder mapBuilder = new MapBuilder();

        return mapBuilder;
    }

    public List splitMap(String newKeyforKey,String newKeyforValue){
        Map m = get();
        ListBuilder listBuilder = ListBuilder.build();
        for(Object en:m.entrySet()){
            Map.Entry entry = ((Map.Entry)en);
            MapBuilder mapBuilder = MapBuilder.build();
            mapBuilder.add(newKeyforKey,entry.getKey());
            mapBuilder.add(newKeyforValue,entry.getValue());
            listBuilder.add(mapBuilder.get());

        }
        return listBuilder.get();
    }

    @Show
    public MapBuilder addSortRefrence(MapBuilder ref) {
        this.ref = ref;
        return this;
    }

    @Show
    public MapBuilder sequnPinyin() {
        return sequnPinyinPrivate();
    }

    private MapBuilder sequnPinyinPrivate() {
        final MapBuilder mapBuilder = this;
        mapBuilder.pinyin = new TreeMap<Object, String>();
        if (mapBuilder.pinyin != null) {
            if (ref == null) {
                ref = MapBuilder.build();
            }
            final List arraylist = new ArrayList(ref.get().keySet());
            mapBuilder.map = new TreeMap(new Comparator<Object>() {
                @Override
                public int compare(Object o, Object o2) {

                    int i1 = arraylist.indexOf(o);
                    int i2 = arraylist.indexOf(o2);

                    if (i1 == -1 && i2 != -1) {
                        return -1;
                    } else if (i1 != -1 && i2 == -1) {
                        return 1;
                    } else if (i1 != -1 && i2 != -1) {
                        int i = i1 - i2;
                        if (i < 0) {
                            return -1;
                        } else if (i > 0) {
                            return 1;
                        } else {
                            return 0;
                        }
                    } else {


                        if ((mapBuilder.pinyin.get(o)) == null && (mapBuilder.pinyin.get(o2)) != null) {
                            return -1;
                        } else if ((mapBuilder.pinyin.get(o)) != null && (mapBuilder.pinyin.get(o2)) == null) {
                            return 1;
                        } else if ((mapBuilder.pinyin.get(o)) == null && (mapBuilder.pinyin.get(o2)) == null) {
                            return 0;
                        } else {
                            int rs = mapBuilder.pinyin.get(o).toString().compareTo(mapBuilder.pinyin.get(o2).toString());
                            if (rs < 0) {
                                return -1;
                            } else if (rs > 0) {
                                return 1;
                            } else return 0;
                        }
                    }
                }
            });
        }
        return mapBuilder;
    }

    @Show
    public MapBuilder sequnIndices() {
        return sequnIndicesPrivate();
    }

    private MapBuilder sequnIndicesPrivate() {
        final MapBuilder mapBuilder = this;
        mapBuilder.indices = new TreeMap<Object, String>();
        if (mapBuilder.indices != null) {
            mapBuilder.map = new TreeMap(new Comparator<Object>() {
                @Override
                public int compare(Object o, Object o2) {
                    if (((Integer) mapBuilder.indices.get(o)) == null && ((Integer) mapBuilder.indices.get(o2)) != null) {
                        return -1;
                    } else if (((Integer) mapBuilder.indices.get(o)) != null && ((Integer) mapBuilder.indices.get(o2)) == null) {
                        return 1;
                    } else if (((Integer) mapBuilder.indices.get(o)) == null && ((Integer) mapBuilder.indices.get(o2)) == null) {
                        return 0;
                    } else {
                        int rs = ((Integer) mapBuilder.indices.get(o)) - ((Integer) mapBuilder.indices.get(o2));
                        if (rs < 0) {
                            return -1;
                        } else if (rs > 0) {
                            return 1;
                        } else return 0;
                    }
                }
            });
        }
        return mapBuilder;
    }

    @Show
    public Object get(String key) {
        return map.get(key);
    }

    @Show
    public MapBuilder addPinyin(T k, Object v) {
        return addPinyinPrivate(k, v);
    }

    private MapBuilder addPinyinPrivate(T k, Object v) {
        if (pinyin != null)
            pinyin.put(k, v.toString());
        return this;
    }

    @Show
    public MapBuilder remove(T k) {
        return removePrivate(k);
    }

    private MapBuilder removePrivate(T k) {
        if (k == null) {

        } else {
            if (indices != null) {

                if (indices.containsKey(k)) {
                    indices.remove(k);
                }
            } else if (pinyin != null) {
                pinyin.remove(k);
            }
            map.remove(k);

        }
        return this;
    }

    @Show
    public MapBuilder add(T k, Object v) {
        return addPrivate(k, v);
    }
    public Object addReturnSelf(T k, Object v) {
        addPrivate(k, v);
        return v;
    }
    private MapBuilder addPrivate(T k, Object v) {
        if (k == null || v == null || v.toString().equals("null")) {

        } else {
            if (indices != null) {

                if (indices.containsKey(k)) {
                    indices.put(k, indices.get(k));
                } else {
                    indices.put(k, indices.size());
                }
            } else if (pinyin != null) {
//                pinyin.put(k, PinyinHelper.rawTransfer(k.toString()));
            }
            map.put(k, v);

        }
        return this;
    }

    @Show
    public Map get() {
        hold = null;
        return map;
    }

    Class clz;

    public MapBuilder toObject(Class clazz) {
        clz = clazz;
        return this;
    }

    public Class getClz() {
        return clz;
    }
}
